/***********************************************
 This file is part of redia-bapps-main-ios.
 
 Copyright (c) 2015 Redia A/S
 
 Redia-bapps-main-ios is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 redia-bapps-main-ios is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with redia-bapps-main-ios.  If not, see <http://www.gnu.org/licenses/>.
 
 *********************************************** */

//
//  BappsManager.h
//  bapps
//
//  Created by Nikolaj Tørring on 8/1/13.
//  Copyright (c) 2013 redia. All rights reserved.
//

#define BARPCMANAGER_SESSIONLIFETIME 1200 // TRUE VALUE
//#define BARPCMANAGER_SESSIONLIFETIME 60 // TEST VALUE ONE MINUTE
//#define BARPCMANAGER_SESSIONLIFETIME 2

#import <Foundation/Foundation.h>
#import "JSONRPCClient.h"
#import "BASearchResult.h"
#import "BAPatron.h"
#import "BAStandardResultObject.h"
#import "JSONRPCClient.h"
#import "JSONEncodingHelperMethods.h"
#import "BARPCHelper.h"
#import "BAFullRecord.h"
#import "BALibrary.h"
#import "BASupportInfo.h"

#ifdef BA_LIBRARIAN_BUILD
#import "LBHoldingItem.h"
#import "LBAutoCompletionListContainer.h"
#endif

#import "defines.h"

#define BARPCMANAGER_DEFAULT_LANGUAGE @"da"

@interface BARPCManager : NSObject


@property (strong, nonatomic) NSString *language; //!< The language that messages from the server will be returned in.
@property (assign, nonatomic) NSTimeInterval reservationsLastUpdated;
@property (assign, nonatomic) NSTimeInterval newsLastUpdated;

@property (copy, nonatomic) NSString* currentPHPSessionID;
@property (copy, nonatomic) NSString* currentRouteIDCookie;

@property (nonatomic, strong) NSDictionary* cookiesDict;

@property (nonatomic, strong, readonly) NSString* libraryId;
@property (nonatomic, strong, readonly) NSString* libraryApiKey;

@property (readonly, nonatomic) NSTimeInterval sessionTimestamp; //!< This timestamp keeps track of the last time an authenticated action was performed.

@property (nonatomic) BOOL isUsingDevServer;

+(void)updateAuthenticatedSessionTimestamp;
+(void)invalidateAuthenticatedSessionTimestamp;
+(BOOL)isStillAuthenticated;

SINGLETON_DECL_GCD(BARPCManager)

- (void)setAndConfigureLibraryId:(NSString*)libraryId;

/**
 This method closes all active connection initiated from a specific view.
 
 @param view A reference to view.
 
 @discussion this method can be used when a viewcontroller is about to be popped to stop all outstanding JSON-RPC requests, for that view. 
 */
+(void)closeConnectionsForView:(id)view;

/**
 This method is used to remove a JSONRPCClient refference from the list of active connections.
 
 @param connection A reference to an instance of JSONRPCClient.
 
 @discussion this method should only be used by the BARPCHelper or BARPCManager classes, and should only be called when the JSONRPCClient instance is done.
 */
+(void)removeConnection:(JSONRPCClient*)connection;


#pragma mark - BApps RPC Methods

+(void)isSupportedAsyncFromView:(id)view
                         device:(NSString*)device
                        appName:(NSString*)appName
                        version:(NSString*)version
                      osVersion:(NSString*)osVersion
                    resultBlock:(void(^)(BASupportInfo* result))resultBlock
                     errorBlock:(void(^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 Initiates a search-query.
 
 @param view A reference to the view calling the function. This i used to cancel all queries for a specific view. 
 @param query A string containing the freetext search query. This parameter is allowed to be empty, if the filters parameter is populated with items.
 @param filters A dictionary of filter keys (provided by the result from getLibraries) to an array of strings with the search terms for that filter.
 @param count An integer determening the size of the resultset.
 @param offset An integer determening the offset for the resultset.
 @param resultBlock A block to be executed when a result is ready. This block has no return value and takes a BASearchResult argument. This parameter must not be NULL.
 @param errorBlock A block to be executed when an error occoures. This block has no return value and takes an String argument that specifies the type of error. This parameter may be NULL.
 
 @discussion language and libraryID properties must be set on the BARPCManager before calling this method.
 */
+(void)searchAsyncFromView:(id)view
                     query:(NSString*)query
                    filter:(NSDictionary*)filters
                     count:(NSUInteger)count
                    offset:(NSUInteger)offset
               resultBlock:(void(^)(BASearchResult* result))resultBlock
                errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 Initiates the download of aditional data for a group of IDs.
 
 @param view A reference to the view calling the function. This i used to cancel all queries for a specific view. 
 @param ids An array of ID strings.
 @param resultBlock A block to be executed when a result is ready. This block has no return value and takes a Dictionarry argument that maps the string-values from the ids-array to an instance of BAStandardResultObject. This parameter must not be NULL.
 @param errorBlock A block to be executed when an error occoures. This block has no return value and takes an String argument that specifies the type of error. This parameter may be NULL.
 
 @discussion language and libraryID must be set on the BARPCManager before calling this method.
 */
+(void)getObjectsAsyncFromView:(id)view
                           ids:(NSArray*)ids
            includeHoldingInfo:(BOOL)includeHoldingInfo
                   resultBlock:(void(^)(NSDictionary* result))resultBlock
                    errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/** DEPRECATED!
 Initiates the download of a list of all libraries.
 
 @param view A reference to the view calling the function. This i used to cancel all queries for a specific view.
 @param resultBlock A block to be executed when a result is ready. This block has no return value and takes an Array of BALibrary objects as argument. This parameter must not be NULL.
 @param errorBlock A block to be executed when an error occoures. This block has no return value and takes an String argument that specifies the type of error. This parameter may be NULL.
 
 @discussion language must be set on the BARPCManager before calling this method.
 *
+(void)getLibrariesAsyncFromView:(id)view
                     resultBlock:(void (^)(NSArray *))resultBlock
                      errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;
*/



/**
 * Returns a {@link StandardObject} with on success the data field
 * set to an map of customerId => library name
 *
 * @param string $uiLanguage
 * @return StandardObject
 */
//public static function getLibraryNames($uiLanguage)
+(void)getLibraryNamesFromView:(id)view
                      resultBlock:(void(^)(NSDictionary* libraryNames))resultBlock
                       errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a {@link StandardObject} with on success the data field
 * set to a {@link Library} object
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
//public static function getLibrarySettings($apiKey, $customerId, $uiLanguage)
+(void)getLibrarySettingsFromView:(id)view
                      resultBlock:(void(^)(BALibrary* library))resultBlock
                       errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Returns a StandardObject with the data field
 * set to an float with the version number
 *
 * @return StandardObject
 */
+(void) versionAsyncFromView:(id)view
                 resultBlock:(void(^)(id result))resultBlock
                  errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject with on success the data field
 * set to the Patron structure (user info).
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param string $username
 * @param string $password
 * @return StandardObject
 */
+(void) authenticateAsyncFromView:(id)view
                         username:(NSString*)username
                         password:(NSString*)password
                      resultBlock:(void(^)(BAPatron* result))resultBlock
                       errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Log out the user if any is log in
 * Returns a success StandardObject with an empty data field
 *
 * @return StandardObject
 */
+(void) deauthenticateAsyncFromView:(id)view
                        resultBlock:(void(^)(id result))resultBlock
                         errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject with on success the data field
 * set to an boolean representing if an user is log in or not
 *
 * @return StandardObject
 */
+(void) isAuthenticatedAsyncFromView:(id)view
                         resultBlock:(void(^)(id result))resultBlock
                          errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Returns a StandardObject with on success the data field
 * set to an array of Branch structures
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
+(void) getBranchesAsyncFromView:(id)view
                     resultBlock:(void(^)(NSArray* result))resultBlock
                      errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/*
* Returns a StandardObject with on success the data field
* set to the SearchResult structure
*
* Filters is not used right now
*
* @param string $customerId
* @param string $uiLanguage
* @param string $query
* @param int $offset
* @param int $count
* @param array $filters (optional)
* @param array $facets (optional) If this isn't set, no default facets is used
* @return StandardObject
*/
+(void) getMoreInSameSeriesAsyncFromView:(id)view
                                   identifier:(NSString *)identifier
                                  offset:(NSUInteger)offset
                                   count:(NSUInteger)count
                                 filters:(NSArray *)filters
                                  facets:(NSArray *)facets
                            resultBlock:(void(^)(BASearchResult* result))resultBlock
                             errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject with on success the data field
 * set to an array of RelatedLoan structures
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param array $isbns
 * @return StandardObject
 */
+(void) getRelatedLoansAsyncFromView:(id)view
                                identifiers:(NSArray*)identifiers
                         resultBlock:(void(^)(NSDictionary *result))resultBlock
                          errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject with on success the data field
 * set to an array of Creator structures
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param array $creators
 * @return StandardObject
 */
+(void) getAboutCreatorAsyncFromView:(id)view
                             creators:(NSArray*)creators
                         resultBlock:(void(^)(NSDictionary *result))resultBlock
                          errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Returns a StandardObject with on success the data field
 * set to an array of Review structures
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param array $reviewQueries
 * @return StandardObject
 */
+(void) getReviewsAsyncFromView:(id)view
                   identifiers:(NSArray*)identifiers
                    resultBlock:(void(^)(NSDictionary *result))resultBlock
                     errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject with on success the data field
 * set to an array of CoverUrl structures
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param array $coverUrlQueries
 * @return StandardObject
 */
+(void) getCoverUrlsAsyncFromView:(id)view
                  coverUrlQueries:(NSArray*)coverUrlQueries
                      resultBlock:(void(^)(NSDictionary* result))resultBlock
                       errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Returns a StandardObject with on success the data field
 * set to a map of identifier => StandardObject containing
 * a Availability structures on success
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param string[] $identifiers
 * @return StandardObject
 */
//php: public static function getAvailability($customerId, $uiLanguage, $identifiers, sendHoldingInfo = true)
+(void) getAvailabilityAsyncFromView:(id)view
                         identifiers:(NSArray*)identifiers
                  includeHoldingInfo:(BOOL)includeHoldingInfo
                            resultBlock:(void(^)(NSDictionary* result))resultBlock
                             errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Returns a StandardObject with on success the data field
 * set to an array of Reservation structures
 *
 * Return error if no user is logged in
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
+(void) getReservationsAsyncFromView:(id)view
                         resultBlock:(void(^)(NSArray* reservations))resultBlock
                          errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject with on success the data field
 * set to a map of reservationId => StandardObject representing
 * success or failure on removal of reservation
 *
 * Return error if no user is logged in
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param string[] $reservationIds
 * @return StandardObject
 */
+(void) removeReservationsAsyncFromView:(id)view
                         reservationIds:(NSArray*)reservationIds
                            resultBlock:(void(^)(id result))resultBlock
                             errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a StandardObject representing success or failure.
 *
 * Return error if no user is logged in
 *
 * @param string $customerId
 * @param string $uiLanguage
 * @param string $reservationId
 * @param string $reservationPickUpBranch (optional) If not set, user default is picked
 * @param int $reservationValidFrom (optional) If not set, now is picked
 * @param int $reservationValidTo (optional) If not set, now + 180 days is picked
 * @return StandardObject
 */
+(void) addReservationAsyncFromView:(id)view
                      reservationId:(NSString*)reservationId
                        resultBlock:(void(^)(id result))resultBlock
                         errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;



/**
 * Returns a {@link StandardObject} with on success the data field
 * set to a map of loanId => {@link StandardObject} containing
 * a {@link Loan} structures on success
 *
 * Return error if no user is logged in
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @param string[] $loanIds
 * @return StandardObject
 */
//public static function renewLoans($apiKey, $customerId, $uiLanguage, $loanIds)
+(void) renewLoansAsyncFromView:(id)view
                        loanIds:(NSArray*)loanIds
                    resultBlock:(void(^)(NSDictionary* result))resultBlock
                     errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Returns a {@link StandardObject} with on success the data field
 * set to a map of loanId => {@link StandardObject} containing
 * a {@link Loan} structures on success
 *
 * Return error if no user is logged in
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
//public static function renewAllLoans($apiKey, $customerId, $uiLanguage)
+(void) renewAllLoansAsyncFromView:(id)view
                       resultBlock:(void(^)(NSDictionary* result))resultBlock
                        errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;

/**
 * Returns a {@link StandardObject} with on success the data field
 * set to an array of {@link Loan} structures
 *
 * Return error if no user is logged in
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
//public static function getLoans($apiKey, $customerId, $uiLanguage)
+(void) getLoansAsyncFromView:(id)view
                        resultBlock:(void(^)(NSArray* loans))resultBlock
                         errorBlock:(void (^)(int errorCode, NSString* errorMessage))errorBlock;


/**
 * Asks the server for a list of libraries and their opening times.
 * On success invokes the resultBlock with a list of BAOpeningHours objects.
 *
 * @param string view The view controller from which this call is initiated.
 * @param block resultBlock The block to invoke on success.
 * @param block errorBlock The block to invoke on error.
 */
+(void)getOpeningHoursAsyncFromView:(id)view
                        resultBlock:(void (^)(NSArray *result))resultBlock
                         errorBlock:(void (^)(int errorCode, NSString *errorMessage))errorBlock;

/**
 * Performs a search for more records from the same creator.
 * On success the resultBlock is invoked on a BASearchResult object.
 *
 * @param string view The view controller from which this call is initiated.
 * @param string $identifier The identifier from a previously retrieved record.
 *                           This is the basis for the search.
 * @param NSUInteger offset 
 * @param NSUInteger count
 * @param NSDictionary filters [optional] Search filters
 * @param NSArray facets [optional]
 * @param block resultBlock The block to invoke on success.
 * @param block errorBlock The block to invoke on error.
 */
+(void)getMoreByCreatorFromView:(id)view
                     identifier:(NSString*)identifier
                         offset:(NSUInteger)offset
                          count:(NSUInteger)count
                        filters:(NSDictionary *)filters
                         facets:(NSArray *)facets
                    resultBlock:(void (^)(BASearchResult *results))resultBlock
                     errorBlock:(void (^)(int errorCode, NSString *errorMessage))errorBlock;

/**
 * Returns a {@link StandardObject} with on success the data field
 * set to an array of {@link Event} structures
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
//public static function loadAllEvents($apiKey, $customerId, $uiLanguage) {
+(void)loadAllEventsFromView:(id)view
                 resultBlock:(void (^)(NSArray *results))resultBlock
                  errorBlock:(void (^)(int errorCode, NSString *errorMessage))errorBlock;

/**
 * Returns a {@link StandardObject} with on success the data field
 * set to an array of {@link News} structures
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @return StandardObject
 */
//public static function loadAllNews($apiKey, $customerId, $uiLanguage) {
+(void)loadAllNewsFromView:(id)view
                 resultBlock:(void (^)(NSArray *results))resultBlock
                  errorBlock:(void (^)(int errorCode, NSString *errorMessage))errorBlock;


/**
 * Returns a {@link StandardObject} with on success the data field
 * set to an array of {@link SearchResultWithTitle} structures
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @param integer $nofLists Should be a positive integer, if it's not, a value is tried retrieved from the configuration file
 * @param integer $listSize Should be a positive integer, if it's not, a value is tried retrieved from the configuration file
 * @return StandardObject
 */
//public static function getPopular($apiKey, $customerId, $uiLanguage, $nofLists = null, $listSize = null)
+(void)getPopularAsyncFromView:(id)view
                     listCount:(NSUInteger)listCount
                      listSize:(NSUInteger)listSize
                   resultBlock:(void (^)(NSArray *))resultBlock
                    errorBlock:(void (^)(int, NSString *))errorBlock;


/**
 * Returns a {@link StandardObject} with on success the data field
 * set to a map of $materialnumber => {@link StandardObject} containing
 * a {@link FullRecord} structures on success
 *
 * $sendHoldingInfo indicates whether the holding data should be returned
 *
 * @param string $apiKey
 * @param string $customerId
 * @param string $uiLanguage
 * @param string[] $materialnumber
 * @param bool $sendHoldingInfo (default true)
 * @return StandardObject
 */
//public static function getObjectByBarcodeId($apiKey, $customerId, $uiLanguage, $materialnumber, $sendHoldingInfo = true) {
+(void)getObjectByBarcodeIdFromView:(id)view
                     materialnumber:(NSString*)materialnumber
                    sendHoldingInfo:(BOOL)sendHoldingInfo
                        resultBlock:(void (^)(BAFullRecord *))resultBlock
                         errorBlock:(void (^)(int errorCode, NSString *errorMessage))errorBlock;

#pragma mark - General

-(NSString*)getNextServerUrlString;

-(NSArray*)serverUrlStrings;

+ (void)performRPCMethod:(NSString *)method args:(id)args requestId:(NSInteger)requestId view:(id)view resultBlock:(BARpcResultBlock)resultBlock errorBlock:(BARpcErrorBlock)errorBlock;


@end
